package com.keste.adf.ui.login;

import java.io.IOException;
import java.io.Serializable;

import java.util.Hashtable;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;

import javax.management.Descriptor;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.modelmbean.ModelMBeanInfo;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

import javax.naming.Context;

import javax.security.auth.Subject;

import javax.security.auth.callback.CallbackHandler;

import javax.security.auth.login.FailedLoginException;

import javax.security.auth.login.LoginException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import weblogic.security.SimpleCallbackHandler;
import weblogic.security.providers.authentication.SQLAuthenticatorMBean;
import weblogic.security.services.Authentication;

import weblogic.servlet.security.ServletAuthentication;


public class SQLAuthenticatorAdapter implements Serializable {
    private static final String MBEAN_INTERFACE = "weblogic.security.providers.authentication.SQLAuthenticatorMBean";
    @SuppressWarnings("compatibility:4260081426626231468")
    private static final long serialVersionUID = 1L;
    private MBeanServerConnection connection;
    private JMXConnector connector;
    private ObjectName providerON;
    
    
    public boolean userExists(String loginId) throws Exception {

        SQLAuthenticatorMBean skjdf;
    
        return (Boolean)connection.invoke(providerON, "userExists",
                          new Object[] { loginId},
                          new String[] { "java.lang.String"});
    }
    
    public void createUser(String username, String password,
                           String description) throws Exception {
        
        connection.invoke(providerON, "createUser",
                          new Object[] { username, password, description},
                          new String[] { "java.lang.String",
                                         "java.lang.String",
                                         "java.lang.String" });
    }
    
    public void createGroup(String groupName, String description) throws Exception {
        connection.invoke(providerON, "createGroup",
                          new Object[] { groupName, description },
                          new String[] { "java.lang.String",
                                         "java.lang.String" });
    }
    
    public void addMemberToGroup(String groupName, String username)throws Exception{
        connection.invoke(providerON, "addMemberToGroup",
                          new Object[] { groupName, username },
                          new String[] { "java.lang.String", "java.lang.String" });
    }

    public void changeUserPassword(String username, String oldPassword,
                                   String newPassword) throws Exception {
        connection.invoke(providerON, "changeUserPassword",
                          new Object[] { username, oldPassword, newPassword },
                          new String[] { "java.lang.String",
                                         "java.lang.String",
                                         "java.lang.String" });
    }
    
    public boolean isMember(String parentGroupName, String memberUserOrGroupName, boolean recursive)throws Exception{
        return (Boolean) connection.invoke(providerON, "isMember",
                          new Object[] { parentGroupName, memberUserOrGroupName, recursive },
                          new String []{"java.lang.String", "java.lang.String", "java.lang.Boolean"});
    }
    
    private ObjectName getAuthenticationProviderObjectName(String type)throws Exception{
       
            ObjectName defaultRealm = getDefaultRealm();
            ObjectName[] atnProviders =
                (ObjectName[])connection.getAttribute(defaultRealm,
                                                      "AuthenticationProviders");
            ObjectName MBTservice =
                new ObjectName("com.bea:Name=MBeanTypeService,Type=weblogic.management.mbeanservers.MBeanTypeService");
            for (int p = 0; atnProviders != null && p < atnProviders.length;
                 p++) {
                ObjectName provider = atnProviders[p];
                ModelMBeanInfo info =
                    (ModelMBeanInfo)connection.getMBeanInfo(provider);
                Descriptor desc = info.getMBeanDescriptor();
                String className =
                    (String)desc.getFieldValue("interfaceClassName");
                String[] mba =
                    (String[])connection.invoke(MBTservice, "getSubtypes",
                                                new Object[] { type },
                                                new String[] { "java.lang.String" });
                for (int i = 0; i < mba.length; i++) {
                    if (mba[i].equals(className)) {
                        return provider;
                    }
                }
            }
            return null;
    }
    private ObjectName getDefaultRealm() throws Exception {
        ObjectName service =
            new ObjectName("com.bea:Name=DomainRuntimeService,Type=weblogic.management.mbeanservers.domainruntime.DomainRuntimeServiceMBean");
        ObjectName domainMBean =
            (ObjectName)connection.getAttribute(service, "DomainConfiguration");
        ObjectName securityConfiguration =
            (ObjectName)connection.getAttribute(domainMBean,
                                                "SecurityConfiguration");
        ObjectName defaultRealm =
            (ObjectName)connection.getAttribute(securityConfiguration,
                                                "DefaultRealm");
        return defaultRealm;
    }
    public void connect(){
        String hostname = "localhost";
        String username = "weblogic";
        String password = "welcome1";
        int port = 7101;
        connect(hostname, username, password, port);
    }
    
    public void connect(String hostname, String username, String password, int port){
        try {       
            String protocol = "t3";
            String jndi =
                "/jndi/weblogic.management.mbeanservers.domainruntime";
            JMXServiceURL serviceURL =
                new JMXServiceURL(protocol, hostname, port, jndi);
            Hashtable env = new Hashtable();
            env.put(Context.SECURITY_PRINCIPAL, username);
            env.put(Context.SECURITY_CREDENTIALS, password);
            env.put(JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES,
                    "weblogic.management.remote");
            env.put("jmx.remote.x.request.waiting.timeout", new Long(10000));
            connector = JMXConnectorFactory.connect(serviceURL, env);
            connection = connector.getMBeanServerConnection();
            providerON = getAuthenticationProviderObjectName(MBEAN_INTERFACE);
        } catch (Exception ex) {
            ex.printStackTrace();
            //throw new RuntimeException(ex);
        }
    }
    public void close(){
        try {
            connector.close();
        } catch (IOException ioe) {
            throw new RuntimeException(ioe);
        }
    }
    
    
    public void doLogin(String in_userName, String in_Password)
    {
        String un = in_userName;
        byte[] pw = in_Password.getBytes();
        FacesContext ctx = FacesContext.getCurrentInstance();
        HttpServletRequest request =
        (HttpServletRequest)ctx.getExternalContext().getRequest();
        CallbackHandler handler = new SimpleCallbackHandler(un, pw);
        
        try {
            Subject mySubject = Authentication.login(handler);
            ServletAuthentication.runAs(mySubject, request);
            ServletAuthentication.generateNewSessionID(request);
            String loginUrl = "/adfAuthentication?success_url=/faces" + 
            ctx.getViewRoot().getViewId();
            HttpServletResponse response = 
            (HttpServletResponse)ctx.getExternalContext().getResponse();
            sendForward(request, response, loginUrl);
        } catch (FailedLoginException fle) {
            FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR,
            "Incorrect Username or Password",
            "An incorrect Username or Password" +
            " was specified");
            ctx.addMessage(null, msg);
        } catch (LoginException le) {
            reportUnexpectedLoginError("LoginException", le);
        }
        return ;
    }
    
    private void sendForward(HttpServletRequest request, 
    HttpServletResponse response,
    String forwardUrl){
    FacesContext ctx = FacesContext.getCurrentInstance();
    RequestDispatcher dispatcher = request.getRequestDispatcher(forwardUrl);
    try {
    dispatcher.forward(request, response);
    } catch (ServletException se) {
    reportUnexpectedLoginError("ServletException", se);
    } catch (IOException ie) {
    reportUnexpectedLoginError("IOException", ie);
    }
    ctx.responseComplete();
    }
    
    private void reportUnexpectedLoginError(String errType, Exception e){
      FacesMessage msg =
        new FacesMessage(FacesMessage.SEVERITY_ERROR, "Unexpected error during login",
                         "Unexpected error during login (" + errType + 
                         "), please consult logs for detail");
      FacesContext.getCurrentInstance().addMessage(null, msg);
      e.printStackTrace();
    }
}
